package com.scarecrow.olga.input {
	
	import com.scarecrow.olga.error.VerboseError;
	import com.scarecrow.olga.input.event.KeyboardInputEvent;
	import com.scarecrow.olga.input.gamepads.events.JoystickButtonsEvent;
	import com.scarecrow.olga.input.gamepads.events.JoystickLowTriggerEvent;
	import com.scarecrow.olga.input.gamepads.events.JoystickMenuEvent;
	import com.scarecrow.olga.input.gamepads.events.JoystickStickButtonsEvent;
	import com.scarecrow.olga.input.gamepads.events.JoystickStickEvent;
	import com.scarecrow.olga.input.gamepads.events.JoystickTriggerEvent;
	import com.scarecrow.olga.input.gamepads.JoystickManager;
	import flash.display.Stage;
	import flash.events.EventDispatcher;
	import flash.events.KeyboardEvent;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	import flash.utils.Dictionary;
	import flash.utils.getTimer;
	
	/**
	 * ...
	 * @author Santiago.J.Elizalde
	 */
	public class InputManager {
		
		private var _enabled:Boolean = true;
		private var _stage:Stage;
		private var joystick:JoystickManager;
		
		private var pressedKeys:Object;
		private var keyRepeatCounters:Object;
		
		private var mouseDown:Boolean;
		private var mousePos:Point;
		
		public var messageBroadcaster:EventDispatcher;
		
		public function InputManager() {
			resetManager();
		}
		
		public function set stage(value:Stage):void {
			if(_stage) return;
			_stage = value;
			if (_enabled) { 
				enableListeners();
			}
		}
		
		private function enableJoystick():void {
			joystick = new JoystickManager();
		}
		
		public function enableListeners():void {
			if(_stage) {
				_stage.addEventListener(MouseEvent.CLICK, clickHandler);
				_stage.addEventListener(MouseEvent.MOUSE_WHEEL, wheelHandler);
				_stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
				_stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
				_stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
				_stage.addEventListener(KeyboardEvent.KEY_UP, keyUpHandler);
			}
		}
		
		public function disableListeners():void {
			if(_stage) {
				_stage.removeEventListener(MouseEvent.CLICK, clickHandler);
				_stage.removeEventListener(MouseEvent.MOUSE_WHEEL, wheelHandler);
				_stage.removeEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
				_stage.removeEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
				_stage.removeEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
				_stage.removeEventListener(KeyboardEvent.KEY_UP, keyUpHandler);
				resetManager();
			}
		}
		
		public function isKeyBeingPressed(keyChar:String):Boolean {
			return pressedKeys[keyChar.toUpperCase()];
		}
		
		public function keyRepeatCount(keyChar:String):uint {
			return keyRepeatCounters[keyChar.toUpperCase()];
		}
		
		public function keyPressTime(keyChar:String):uint {
			return pressedKeys[keyChar.toUpperCase()];
		}
		
		public function get keysBeingPressed():Array {
			var result:Array = [];
			for (var item:String in pressedKeys) {
				result.push(item);
			}
			return result;
		}
		
		public function get mousePositionOnStage():Point {
			mousePos.x = _stage.mouseX;
			mousePos.y = _stage.mouseY;
			return mousePos;
		}
		
		public function get isMousePressed():Boolean {
			return mouseDown;
		}
		
		public function get enabled():Boolean {
			return _enabled;
		}
		
		public function set enabled(value:Boolean):void {
			if(value == _enabled) return;
			_enabled = value;
			_enabled ? enableListeners() : disableListeners();
		}
		
		// ----- Event Handlers -------------------------------------------------------------------------
		
		private function keyUpHandler(e:KeyboardEvent):void {
			
			var keyString:String = String.fromCharCode(e.charCode).toUpperCase();
			var event:KeyboardInputEvent = new KeyboardInputEvent(KeyboardInputEvent.KEY_UP);
			event.alt = e.altKey;
			event.ctrl = e.ctrlKey;
			event.shift = e.shiftKey;
			event.pressedKey = keyString;
			event.charCode = e.keyCode;
			event.holdTime = (getTimer() - pressedKeys[keyString])/1000;//TODO: use a "GameTimer" timestamp here.
			event.repeatCount = keyRepeatCounters[keyString];
			
			delete pressedKeys[keyString];
			delete keyRepeatCounters[keyString];
			
			messageBroadcaster.dispatchEvent(event);
		}
		
		private function keyDownHandler(e:KeyboardEvent):void {
			
			var keyString:String = String.fromCharCode(e.charCode).toUpperCase();
			var event:KeyboardInputEvent;
			if(pressedKeys[keyString]) {
				event = new KeyboardInputEvent(KeyboardInputEvent.KEY_REPEAT);
				event.holdTime = (getTimer() - pressedKeys[keyString]) / 1000;//TODO: use a "GameTimer" timestamp here.;
				keyRepeatCounters[keyString]++;
			} else {
				event = new KeyboardInputEvent(KeyboardInputEvent.KEY_DOWN);
				event.holdTime = 0;
				pressedKeys[keyString] = getTimer();//TODO: use a "GameTimer" timestamp here.
				keyRepeatCounters[keyString] = 0;
			}
			event.charCode = e.keyCode;
			event.alt = e.altKey;
			event.ctrl = e.ctrlKey;
			event.shift = e.shiftKey;
			event.pressedKey = keyString;
			event.repeatCount = keyRepeatCounters[keyString];
			
			messageBroadcaster.dispatchEvent(event);
		}
		
		private function mouseUpHandler(e:MouseEvent):void {
			mouseDown = false;
			messageBroadcaster.dispatchEvent(e);
		}
		
		private function mouseDownHandler(e:MouseEvent):void {
			mouseDown = true;
			messageBroadcaster.dispatchEvent(e);
		}
		
		private function wheelHandler(e:MouseEvent):void {
			messageBroadcaster.dispatchEvent(e);
		}
		
		private function clickHandler(e:MouseEvent):void {
			messageBroadcaster.dispatchEvent(e);
		}
		
		// ----- Utility Functions --------------------------------------
		
		private function resetManager():void {
			pressedKeys = new Object();
			keyRepeatCounters = new Object();
			mouseDown = false;
			mousePos = new Point();
			messageBroadcaster = new EventDispatcher();
		}
	}
}